home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / EDITOR / TDE20E.ARJ / DIRLIST.C < prev    next >
C/C++ Source or Header  |  1992-06-05  |  28KB  |  851 lines

  1. /*
  2.  * I wrote this function because I'm so stupid, I constantly forget
  3.  * file names and directory stuff.  The main function prompts for a
  4.  * subdirectory name or a search path.  The default search path is the
  5.  * cwd (current working directory).  In addition to being stupid, I'm also
  6.  * lazy.  If the user types a subdirectory name, I think we can assume he
  7.  * wants to list all files w/o having to type *.*   Let's save the cwd on
  8.  * whatever drive the user wishes to search, so we can restore it we get
  9.  * thru dir'ing.  Use the standard DOS functions to get and set directories.
  10.  *
  11.  *  The search pattern can contain wild card chars, valid file names, or
  12.  *  a valid subdirectory name.
  13.  *
  14.  * New editor name:  tde, the Thomson-Davis Editor.
  15.  * Author:           Frank Davis
  16.  * Date:             June 5, 1991, version 1.0
  17.  * Date:             July 29, 1991, version 1.1
  18.  * Date:             October 5, 1991, version 1.2
  19.  * Date:             January 20, 1992, version 1.3
  20.  * Date:             February 17, 1992, version 1.4
  21.  * Date:             April 1, 1992, version 1.5
  22.  * Date:             June 5, 1992, version 2.0
  23.  *
  24.  * This code is released into the public domain, Frank Davis.
  25.  *    You may distribute it freely.
  26.  */
  27.  
  28. #include "tdestr.h"
  29. #include "common.h"
  30. #include "define.h"
  31. #include "tdefunc.h"
  32. #include <malloc.h>
  33.  
  34.  
  35. /*
  36.  * Name:    dir_help
  37.  * Purpose: To prompt the user and list the directory contents
  38.  * Date:    February 13, 1992
  39.  * Passed:  window:  pointer to current window
  40.  */
  41. int  dir_help( WINDOW *window )
  42. {
  43. char dname[MAX_COLS+2]; /* directory search pattern */
  44. char stem[MAX_COLS+2];  /* directory stem */
  45. int rc;
  46.  
  47.    un_copy_line( window->cursor, window, TRUE );
  48.    dname[0] = '\0';
  49.    /*
  50.     * search path or pattern
  51.     */
  52.    if (get_name( dir1,
  53.                  window->bottom_line, dname, g_display.message_color ) == OK) {
  54.       if (validate_path( dname, stem ) == OK) {
  55.          rc = list_and_pick( dname, stem, window );
  56.  
  57.          /*
  58.           * if everything is everything, load in the file selected by user.
  59.           */
  60.          if (rc == OK)
  61.             attempt_edit_display( dname, LOCAL );
  62.       } else
  63.          /*
  64.           * invalid path or file name
  65.           */
  66.          error( WARNING, window->bottom_line, dir2 );
  67.    }
  68.    return( OK );
  69. }
  70.  
  71.  
  72. /*
  73.  * Name:    validate_path
  74.  * Purpose: make sure we got a valid search pattern or subdirectory
  75.  * Date:    February 13, 1992
  76.  * Passed:  dname: search path entered by user
  77.  *          stem:  directory stem is returned
  78.  * Returns: successful or not
  79.  * Notes:   we need to validate the search path or pattern.  if the search
  80.  *            pattern is valid, then we need to get the search stem.
  81.  *          the user may enter a subdirectory or some kind of search pattern.
  82.  *             if the user enters a subdirectory, then there are a few things
  83.  *             we need to take care of  1) find out if the subdirectory is
  84.  *             the root, 2) append a '\' to the subdirectory so we can create
  85.  *             a search pattern for the subdirectory, 3) don't append '\' to
  86.  *             the root, it already has a '\'.
  87.  *          if the user enters a search pattern, then we need to dissect the
  88.  *             search path.  we must create a stem from the search pattern.
  89.  */
  90. int  validate_path( char *dname, char *stem )
  91. {
  92. int rc;
  93. DTA dta;                /* temp disk transfer struct for findfirst, etc. */
  94. int fattr;
  95. int i;
  96. int len;
  97. char *p;
  98. char temp[MAX_COLS+2];  /* directory stem */
  99.  
  100.    /*
  101.     * if path name is void then the current working directory is implied.
  102.     */
  103.    if (dname[0] == '\0') {
  104.       strcpy( dname, stardotstar );
  105.       stem[0] = '\0';
  106.       rc = OK;
  107.    } else {
  108.  
  109.       /*
  110.        * get the attributes of the search pattern, so we can determine if
  111.        * this is a pattern or subdirectory.
  112.        */
  113.       rc = get_fattr( dname, &fattr );
  114.  
  115.       if (rc == OK && (fattr & SUBDIRECTORY)) {
  116.          strcpy( stem, dname );
  117.  
  118.          /*
  119.           * if this is the root directory ( \ ), don't append '\' to it.
  120.           * user entered a subdirectory - append *.* to get contents of
  121.           * subdirectory.
  122.           */
  123.          len = strlen( stem );
  124.          if (stem[len-1] != '\\') {
  125.             strcat( stem, "\\" );
  126.             strcat( dname, "\\" );
  127.          }
  128.          strcat( dname, stardotstar );
  129.  
  130.       /*
  131.        * not a subdirectory.  let's see if any files match the search
  132.        * pattern.
  133.        */
  134.       } else if (rc != ERROR) {
  135.          if ((rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN |
  136.                               SYSTEM | SUBDIRECTORY | ARCHIVE )) == OK) {
  137.  
  138.             /*
  139.              * copy dname to "temp" so we can use "temp" to find the stem.
  140.              *    we need to search the pattern backwards to figure the stem.
  141.              */
  142.             strcpy( temp, dname );
  143.             len = strlen( dname );
  144.             for (i=len,p=temp+len; i>=0; i--) {
  145.                /*
  146.                 *  if we run into the '\' or the ':', then we got a stem.
  147.                 */
  148.                if (*p == '\\' || *p == ':') {
  149.                   p = temp + i;
  150.                   *(p+1) = '\0';
  151.                   break;
  152.                /*
  153.                 * if we're at the beginning of the string, stem == '\0'
  154.                 */
  155.                } else if (i == 0) {
  156.                   *p = '\0';
  157.                   break;
  158.                }
  159.                --p;
  160.             }
  161.             strcpy( stem, temp );
  162.          } else
  163.             rc = ERROR;
  164.  
  165.       /*
  166.        * user did not enter a valid subdirectory name or search pattern.
  167.        */
  168.       } else
  169.          rc = ERROR;
  170.    }
  171.    return( rc );
  172. }
  173.  
  174.  
  175. /*
  176.  * Name:    list_and_pick
  177.  * Purpose: To show matching file names and let user pick a file
  178.  * Date:    February 13, 1992
  179.  * Passed:  dname:  directory search pattern
  180.  *          stem:   stem of directory search pattern
  181.  *          window:  pointer to current window
  182.  * Returns: return code from pick.  rc = OK, then edit a new file.
  183.  * Notes:   real work routine of this function.  save the cwd and let the
  184.  *          user search upwards or downwards thru the directory structure.
  185.  *          since we are doing DOS directory functions, we need to check the
  186.  *            return code after each DOS call for critical errors.
  187.  */
  188. int  list_and_pick( char *dname, char *stem, WINDOW *window )
  189. {
  190. int rc;
  191. DTA dta;                /* disk transfer address for findfirst */
  192. DIRECTORY dir;          /* contains all info for dir display */
  193. unsigned int cnt;       /* number of matching files */
  194. FTYPE *flist, *p;       /* pointer to list of matching files */
  195. char cwd[MAX_COLS];     /* save the current working directory in this buff */
  196. char dbuff[MAX_COLS];   /* temporary directory buff */
  197. char prefix[MAX_COLS];  /* directory prefix  */
  198. int change_directory = FALSE;
  199. int stop;
  200. int len;
  201. int drive;
  202.  
  203.    /*
  204.     * Some algorithms alloc the maximum possible number of files in
  205.     *  a directory, eg. 256 or 512.  Let's count the number of matching
  206.     *  files so we know egxactly how much memory to request from calloc.
  207.     *  Depending on the op system, disk media, disk format, or version of DOS,
  208.     *  the max number of files may vary, anyway, also, additionally.
  209.     */
  210.    rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN | SYSTEM |
  211.                                 SUBDIRECTORY | ARCHIVE );
  212.    if (rc != ERROR) {
  213.       for (cnt=1; (rc = findnext( &dta )) == OK;)
  214.          ++cnt;
  215.       flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) );
  216.    }
  217.    if (rc != ERROR && flist != NULL) {
  218.  
  219.       stop = FALSE;
  220.       /*
  221.        * If user entered drive name in search pattern, find out the drive and
  222.        *   directory stem.
  223.        */
  224.       if (stem[1] == ':') {
  225.  
  226.          /*
  227.           * If the second character of the search pattern is a ':', the
  228.           *   the first character of the pattern should be the drive.
  229.           *   Convert drive to lower case and get a numerical representation.
  230.           * CAVEAT:  In DOS v 2.x, there may be up to 63 logical drives.
  231.           *    this algorithm may blow up if the number of logical drives
  232.           *    is greater than 'Z'.
  233.           * For DOS >= 3, the number of drives is limited to 26, I think.
  234.           */
  235.          drive = stem[0];
  236.          if (drive < 'a')
  237.             drive += 32;
  238.          drive = drive - 'a' + 1;
  239.          rc = get_current_directory( dbuff, drive );
  240.          if (rc == ERROR)
  241.             stop = TRUE;
  242.          else {
  243.  
  244.             /*
  245.              * Put drive letter, ':', and '\' in front of current directory.
  246.              */
  247.             prefix[0] = (char)(drive - 1 + 'a');
  248.             prefix[1] = ':';
  249.             prefix[2] = '\\';
  250.             prefix[3] = '\0';
  251.             strcpy( cwd, prefix );
  252.             strcat( cwd, dbuff );
  253.          }
  254.  
  255.       /*
  256.        * else get current directory from default drive
  257.        */
  258.       } else {
  259.  
  260.          /*
  261.           * 0 = default drive.
  262.           */
  263.          drive = 0;
  264.          rc = get_current_directory( dbuff, drive );
  265.          if (rc == ERROR)
  266.             stop = TRUE;
  267.          else {
  268.  
  269.             /*
  270.              * Put a '\' in front of the current directory.
  271.              */
  272.             prefix[0] = '\\';
  273.             prefix[1] = '\0';
  274.             strcpy( cwd, prefix );
  275.             strcat( cwd, dbuff );
  276.          }
  277.       }
  278.  
  279.       save_screen( );
  280.       while (stop == FALSE) {
  281.          /*
  282.           * If we had enough memory, find all matching file names.  Append
  283.           *   '\\' at the end of subdirectory names so user will know if
  284.           *    name is a directory.  Might as well find everything, because
  285.           *    i also forget subdirectory names, too.
  286.           *
  287.           * when we get here, we have already done: 1) findfirst and findnext,
  288.           *   2) counted the number of matching files, and 3) allocated space.
  289.           */
  290.          p = flist;
  291.          cnt = 0;
  292.  
  293.          rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN | SYSTEM |
  294.                                  SUBDIRECTORY | ARCHIVE );
  295.          if (rc != ERROR) {
  296.  
  297.             /*
  298.              * p is pointer that walks down the file info structure.
  299.              *  save the file name, file size, and directory character,
  300.              *  if needed, for each matching file we find.
  301.              */
  302.             strcpy( p->fname, dta.name );
  303.             p->fsize = dta.size;
  304.             if (dta.attrib & SUBDIRECTORY)
  305.                strcat( p->fname, "\\" );
  306.             for (cnt=1; (rc = findnext( &dta )) == OK; ) {
  307.                ++p;
  308.                strcpy( p->fname, dta.name );
  309.                p->fsize = dta.size;
  310.                if (dta.attrib & SUBDIRECTORY)
  311.                   strcat( p->fname, "\\" );
  312.                cnt++;
  313.             }
  314.          }
  315.  
  316.          if (rc != ERROR) {
  317.             shell_sort( flist, cnt );
  318.  
  319.             /*
  320.              * figure out number of rows, cols, etc... then display dir list
  321.              */
  322.             setup_directory_window( &dir, cnt );
  323.             write_directory_list( flist, dir );
  324.  
  325.             /*
  326.              * Let user select file name or another search directory.
  327.              *  Save the choice in dbuff.  rc == OK if user selected file or dir.
  328.              */
  329.             rc = select_file( flist, stem, &dir );
  330.             strcpy( dbuff, flist[dir.select].fname );
  331.          }
  332.  
  333.          /*
  334.           *  give memory back.
  335.           */
  336.          free( flist );
  337.  
  338.          if (rc == ERROR)
  339.             stop = TRUE;
  340.          else {
  341.             len = strlen( dbuff );
  342.  
  343.             /*
  344.              * If the last character in a file name is '\' then let's
  345.              *   do a dir on selected directory.  See the matching
  346.              *   else when the user selects a file.
  347.              */
  348.             if (dbuff[len-1] == '\\') {
  349.  
  350.                /*
  351.                 * Stem has subdirectory path.  dbuff has selected path.
  352.                 * Create a new dname with stem and dbuff.
  353.                 */
  354.                strcpy( dname, stem );
  355.                strcat( dname, dbuff );
  356.                len = strlen( dname );
  357.                strcpy( dbuff, dname );
  358.  
  359.                /*
  360.                 * The last character in dbuff is '\', because we append the
  361.                 *   '\' to every directory entry in the file list.  Replace
  362.                 *   it with a NULL char then we will have a valid path name.
  363.                 */
  364.                dbuff[len-1] = '\0';
  365.  
  366.                /*
  367.                 * now let's change to the selected subdirectory.
  368.                 */
  369.                rc = set_current_directory( dbuff );
  370.                if (rc == OK) {
  371.  
  372.                   /*
  373.                    * Every time we change directories, we need to get the
  374.                    *   current directory so we will be sure to have the
  375.                    *   correct path.
  376.                    */
  377.                   rc = get_current_directory( dbuff, drive );
  378.                   if (rc == OK) {
  379.                      strcpy( dname, prefix );
  380.                      strcat( dname, dbuff );
  381.                      change_directory = TRUE;
  382.                   }
  383.                }
  384.  
  385.                /*
  386.                 * Validate the new path and allocate memory for the
  387.                 *   matching files.
  388.                 */
  389.                if (rc == OK)
  390.                   rc = validate_path( dname, stem );
  391.                if (rc == OK) {
  392.                   rc = findfirst( &dta, dname, NORMAL | READ_ONLY | HIDDEN |
  393.                                   SYSTEM | SUBDIRECTORY | ARCHIVE );
  394.                   if (rc != ERROR) {
  395.                      for (cnt=1; (rc = findnext( &dta )) == OK;)
  396.                         ++cnt;
  397.                      flist = (FTYPE *)calloc( cnt, sizeof(FTYPE) );
  398.                   }
  399.                }
  400.                if (flist == NULL || rc == ERROR) {
  401.                   stop = TRUE;
  402.                   rc = ERROR;
  403.                }
  404.             } else {
  405.  
  406.                /*
  407.                 *  user selected a file.  store fname in dname and return.
  408.                 */
  409.                rc = OK;
  410.                stop = TRUE;
  411.                strcpy( dname, stem );
  412.                strcat( dname, dbuff );
  413.             }
  414.          }
  415.       }
  416.  
  417.       /*
  418.        * Go back to the current directory if needed.
  419.        */
  420.       if (change_directory)
  421.          set_current_directory( cwd );
  422.       restore_screen( );
  423.    } else {
  424.       /*
  425.        * out of memory
  426.        */
  427.       error( WARNING, window->bottom_line, dir3 );
  428.       rc = ERROR;
  429.    }
  430.    return( rc );
  431. }
  432.  
  433.  
  434. /*
  435.  * Name:    setup_directory_window
  436.  * Purpose: set number of rows and cols in directory window
  437.  * Date:    February 13, 1992
  438.  * Passed:  dir: pointer to directory structure
  439.  *          cnt: number of files
  440.  * Notes:   set up stuff we need to know about how to display files.
  441.  */
  442. void setup_directory_window( DIRECTORY *dir, int cnt )
  443. {
  444. int i;
  445. int wid;
  446. char temp[MAX_COLS];       /* line to output */
  447.  
  448.    /*
  449.     * setup the fixed vars used in dir display.
  450.     *    dir->col =      physical upper left column of dir screen
  451.     *    dir->row =      physical upper left row or line of dir screen
  452.     *    dir->wid =      width of physical screen
  453.     *    dir->hgt =      height of physical screen
  454.     *    dir->max_cols   number of columns of files in dir screen
  455.     *    dir->max_lines  number of lines of files in each column in dir screen
  456.     *    dir->cnt        number of files in list
  457.     */
  458.    dir->col = 3;
  459.    dir->row = 5;
  460.    wid = dir->wid = 72;
  461.    dir->hgt = 16;
  462.    dir->max_cols = 5;
  463.    dir->max_lines = 9;
  464.    dir->cnt = cnt;
  465.  
  466.    /*
  467.     *  Find out how many lines in each column are needed to display
  468.     *     matching files.
  469.     */
  470.    dir->lines = dir->cnt / dir->max_cols + (dir->cnt % dir->max_cols ? 1 : 0);
  471.    if (dir->lines > dir->max_lines)
  472.       dir->lines = dir->max_lines;
  473.  
  474.    /*
  475.     * Find out how many columns of file names we need.
  476.     */
  477.    dir->cols = dir->cnt / dir->lines + (dir->cnt % dir->lines ? 1 : 0);
  478.    if (dir->cols > dir->max_cols)
  479.       dir->cols = dir->max_cols;
  480.  
  481.  
  482.    /*
  483.     * Find the maximun number of file names we can display in help screen.
  484.     */
  485.    dir->avail = dir->lines * dir->cols;
  486.  
  487.    /*
  488.     * Now find the number of file names we do have on the screen.  Every
  489.     *   time we slide the "window", we have to calculate a new nfiles.
  490.     */
  491.    dir->nfiles = dir->cnt > dir->avail ? dir->avail : dir->cnt;
  492.  
  493.    /*
  494.     * A lot of times, the number of matching files will not fit evenly
  495.     *   in our help screen.  The last column on the right will be partially
  496.     *   filled, hence the variable name prow (partial row).  When there are
  497.     *   more file names than can fit on the screen, we have to calculate
  498.     *   prow every time we slide the "window" of files.
  499.     */
  500.    dir->prow = dir->lines - (dir->avail - dir->nfiles);
  501.  
  502.    /*
  503.     * Find out how many "virtual" columns of file names we have.  If
  504.     *   all the files can fit in the dir screen, there will be no
  505.     *   virtual columns.
  506.     */
  507.    if (dir->cnt < dir->avail)
  508.       dir->vcols = 0;
  509.    else
  510.       dir->vcols =  (dir->cnt - dir->avail) / dir->max_lines +
  511.                    ((dir->cnt - dir->avail) % dir->max_lines ? 1 : 0);
  512.  
  513.    /*
  514.     * Find the physical display column in dir screen.
  515.     */
  516.    dir->flist_col[0] = dir->col + 2;
  517.    for (i=1; i<dir->max_cols; i++)
  518.       dir->flist_col[i] = dir->flist_col[i-1] + 14;
  519.  
  520.    /*
  521.     * Now, draw the borders of the dir screen.
  522.     */
  523.    for (i=0; i < dir->hgt; i++) {
  524.       if (i == 0 || i == dir->hgt-1) {
  525.          memset( temp, '─', wid );
  526.          temp[wid] = '\0';
  527.          if (i == 0) {
  528.             temp[0] = '┌';
  529.             temp[wid-1] = '┐';
  530.          } else {
  531.             temp[0] = '└';
  532.             temp[wid-1] = '┘';
  533.          }
  534.       } else {
  535.          memset( temp, ' ', wid );
  536.          temp[wid] = '\0';
  537.          temp[0] = temp[wid-1] = '│';
  538.       }
  539.       s_output( temp, dir->row+i, dir->col, g_display.help_color );
  540.    }
  541.  
  542.    /*
  543.     * Write headings in help screen.
  544.     */
  545.    s_output( dir4, dir->row+1, dir->col+3, g_display.help_color );
  546.    s_output( dir5, dir->row+2, dir->col+3, g_display.help_color );
  547.    s_output( dir6, dir->row+2, dir->col+44, g_display.help_color );
  548.    s_output( dir7, dir->row+14, dir->col+8, g_display.help_color );
  549. }
  550.  
  551.  
  552. /*
  553.  * Name:    write_directory_list
  554.  * Purpose: given directory list, display matching files
  555.  * Date:    February 13, 1992
  556.  * Passed:  flist: pointer to list of files
  557.  *          dir:   directory display structure
  558.  * Notes:   blank out the previous file name and display the new one.
  559.  */
  560. void write_directory_list( FTYPE *flist, DIRECTORY dir )
  561. {
  562. FTYPE *p, *top;
  563. int i;
  564. int j;
  565. int k;
  566. int end;
  567. int line;
  568. int col;
  569. int color;
  570.  
  571.    color = g_display.help_color;
  572.    top = flist;
  573.    for (i=0; i < dir.lines; ++i) {
  574.       p = top;
  575.       end = FALSE;
  576.       for (j=0; j < dir.cols; ++j) {
  577.          col = dir.flist_col[j];
  578.          line = i + dir.row + 4;
  579.  
  580.          /*
  581.           * We need to blank out all lines and columns used to display
  582.           *   files, because there may be some residue from a previous dir
  583.           */
  584.          s_output( "            ", line, col, color );
  585.          if (!end) {
  586.             s_output( p->fname, line, col, color );
  587.             p += dir.lines;
  588.             k = p - flist;
  589.             if (k >= dir.nfiles)
  590.                end = TRUE;
  591.          }
  592.       }
  593.       ++top;
  594.    }
  595. }
  596.  
  597.  
  598. /*
  599.  * Name:    select_file
  600.  * Purpose: To let user select a file from dir list
  601.  * Date:    February 13, 1992
  602.  * Passed:  flist: pointer to list of files
  603.  *          stem:  base directory
  604.  *          dir:   directory display stuff
  605.  * Notes:   let user move thru the file names with the cursor keys
  606.  */
  607. int  select_file( FTYPE *flist, char *stem, DIRECTORY *dir )
  608. {
  609. int ch;         /* input character from user */
  610. int func;       /* function of character input by user */
  611. int fno;        /* index into flist of the file under cursor */
  612. int goodkey;    /* is key a recognized function key? */
  613. int r;          /* current row of cursor */
  614. int c;          /* current column of cursor */
  615. int offset;     /* offset into file list */
  616. int stop;       /* stop indicator */
  617. int stem_len;   /* stem length */
  618. int color;      /* color of help screen */
  619. int file_color; /* color of current file */
  620. int change;     /* boolean, hilite another file? */
  621. int oldr;       /* old row */
  622. int oldc;       /* old column */
  623. char asize[20]; /* ascii file size */
  624. char blank[20]; /* blank out file names */
  625.  
  626.    /*
  627.     * initial everything.
  628.     */
  629.    memset( blank, ' ', 12 );
  630.    blank[12] = '\0';
  631.    c = r = 1;
  632.    ch = fno = offset = 0;
  633.    color = g_display.help_color;
  634.    file_color = g_display.hilited_file;
  635.    goodkey = TRUE;
  636.    stop = FALSE;
  637.    stem_len = strlen( stem );
  638.    s_output( stem, dir->row+1, dir->col+19, color );
  639.    s_output( flist[fno].fname, dir->row+1, dir->col+19+stem_len, color );
  640.    ltoa( flist[fno].fsize, asize, 10 );
  641.    s_output( blank, dir->row+2, dir->col+19, color );
  642.    s_output( asize, dir->row+2, dir->col+19, color );
  643.    itoa( dir->cnt,  asize, 10 );
  644.    s_output( blank, dir->row+2, dir->col+57, color );
  645.    s_output( asize, dir->row+2, dir->col+57, color );
  646.    xygoto( (c-1)*14+dir->col+2, r+dir->row+3 );
  647.    hlight_line( (c-1)*14+dir->col+2, r+dir->row+3, 12, file_color );
  648.    change = FALSE;
  649.    while (stop == FALSE) {
  650.       oldr = r;
  651.       oldc = c;
  652.       ch = getkey( );
  653.       func = getfunc( ch );
  654.  
  655.       /*
  656.        * User may have redefined the Enter and ESC keys.  Make the Enter key
  657.        * perform a Rturn in this function. Make the ESC key do an AbortCommand.
  658.        */
  659.       if (ch == RTURN)
  660.          func = Rturn;
  661.       else if (ch == ESC)
  662.          func = AbortCommand;
  663.  
  664.       switch (func) {
  665.          case Rturn       :
  666.          case NextLine    :
  667.          case BegNextLine :
  668.             stop = TRUE;
  669.             break;
  670.          case AbortCommand :
  671.             stop = TRUE;
  672.             break;
  673.          case LineUp :
  674.             if (r > 1) {
  675.                change = TRUE;
  676.                --r;
  677.             } else {
  678.                r = dir->lines;
  679.                change = TRUE;
  680.                if (offset == 0 || c > 1) {
  681.                   if (c > 1)
  682.                      --c;
  683.                } else if (dir->vcols > 0 && offset > 0 && c == 1) {
  684.                   /*
  685.                    * recalculate the dir display stuff.
  686.                    */
  687.                   offset -= dir->lines;
  688.                   recalculate_dir( dir, flist, offset );
  689.                }
  690.             }
  691.             goodkey = TRUE;
  692.             break;
  693.          case LineDown :
  694.             if (r < dir->prow) {
  695.                change = TRUE;
  696.                ++r;
  697.             } else if (r < dir->lines && c != dir->cols) {
  698.                change = TRUE;
  699.                ++r;
  700.             } else {
  701.                change = TRUE;
  702.                r = 1;
  703.                if (offset == dir->vcols * dir->lines || c < dir->cols) {
  704.                   if (c < dir->cols)
  705.                      ++c;
  706.                } else if (dir->vcols > 0 && offset < dir->vcols * dir->lines &&
  707.                          c == dir->cols) {
  708.                   offset += dir->lines;
  709.                   recalculate_dir( dir, flist, offset );
  710.                }
  711.             }
  712.             goodkey = TRUE;
  713.             break;
  714.          case CharLeft :
  715.             if (offset == 0 || c > 1) {
  716.                if (c > 1) {
  717.                   change = TRUE;
  718.                   --c;
  719.                }
  720.             } else if (dir->vcols > 0 && offset > 0 && c == 1) {
  721.                change = TRUE;
  722.  
  723.                /*
  724.                 * recalculate the dir display stuff.
  725.                 */
  726.                offset -= dir->lines;
  727.                recalculate_dir( dir, flist, offset );
  728.             }
  729.             goodkey = TRUE;
  730.             break;
  731.          case CharRight :
  732.             if (offset == dir->vcols * dir->lines || c < dir->cols) {
  733.                if (c < dir->cols) {
  734.                   change = TRUE;
  735.                   ++c;
  736.                   if (c == dir->cols) {
  737.                      if ( r > dir->prow)
  738.                         r = dir->prow;
  739.                   }
  740.                }
  741.             } else if (dir->vcols > 0 && offset < dir->vcols * dir->lines &&
  742.                          c == dir->cols) {
  743.                change = TRUE;
  744.                offset += dir->lines;
  745.                recalculate_dir( dir, flist, offset );
  746.                if (r > dir->prow)
  747.                   r = dir->prow;
  748.             }
  749.             goodkey = TRUE;
  750.             break;
  751.          case BegOfLine :
  752.             change = TRUE;
  753.             c = r = 1;
  754.             goodkey = TRUE;
  755.             break;
  756.          case EndOfLine :
  757.             change = TRUE;
  758.             r = dir->prow;
  759.             c = dir->cols;
  760.             goodkey = TRUE;
  761.             break;
  762.          case ScreenDown :
  763.             change = TRUE;
  764.             r = (c == dir->cols) ? r = dir->prow : dir->lines;
  765.             goodkey = TRUE;
  766.             break;
  767.          case ScreenUp :
  768.             change = TRUE;
  769.             r = 1;
  770.             goodkey = TRUE;
  771.             break;
  772.       }
  773.       if (goodkey) {
  774.          s_output( blank, dir->row+1, dir->col+19+stem_len, color );
  775.          fno = offset + (c-1)*dir->lines + (r-1);
  776.          s_output( flist[fno].fname, dir->row+1, dir->col+19+stem_len, color );
  777.          ltoa( flist[fno].fsize, asize, 10 );
  778.          s_output( blank, dir->row+2, dir->col+19, color );
  779.          s_output( asize, dir->row+2, dir->col+19, color );
  780.          xygoto( (c-1)*14+dir->col+2, r+dir->row+3 );
  781.          goodkey = FALSE;
  782.          if (change) {
  783.             hlight_line( (oldc-1)*14+dir->col+2, oldr+dir->row+3, 12, color );
  784.             hlight_line( (c-1)*14+dir->col+2, r+dir->row+3, 12, file_color );
  785.             change = FALSE;
  786.          }
  787.       }
  788.    }
  789.    dir->select = fno;
  790.    return( func == AbortCommand ? ERROR : OK );
  791. }
  792.  
  793.  
  794. /*
  795.  * Name:    recalculate_dir
  796.  * Purpose: To recalcute dir structure when cursor goes ahead or behind screen
  797.  * Date:    February 13, 1992
  798.  * Passed:  dir:    pointer to file structure
  799.  *          flist:  pointer to file structure
  800.  *          offset: number of files from beginning of flist
  801.  * Notes:   Find new number of files on the screen.  Then, find out
  802.  *          how many files names are in the last column.
  803.  */
  804. void recalculate_dir( DIRECTORY *dir , FTYPE *flist, int offset )
  805. {
  806. register int off;
  807.  
  808.    off = offset;
  809.    dir->nfiles = (dir->cnt - off) > dir->avail ? dir->avail :
  810.                 (dir->cnt - off);
  811.    dir->prow = dir->lines - (dir->avail - dir->nfiles);
  812.    write_directory_list( flist+off, *dir );
  813. }
  814.  
  815.  
  816. /*
  817.  * Name:    shell_sort
  818.  * Purpose: To sort file names
  819.  * Date:    February 13, 1992
  820.  * Passed:  flist: pointer to file structure
  821.  *          cnt:   number of files to sort
  822.  */
  823. void shell_sort( FTYPE *flist, int cnt )
  824. {
  825. register int i;
  826. int inc;
  827. int limit;
  828. int change;
  829. FTYPE temp;
  830. FTYPE *fl;
  831.  
  832.    fl = flist;
  833.    inc = cnt / 2;
  834.    while (inc) {
  835.       limit = cnt - inc - 1;
  836.       do {
  837.          change = FALSE;
  838.          for (i=0; i<=limit; i++) {
  839.             if (memcmp( fl[i].fname, fl[i+inc].fname, 14 ) > 0) {
  840.                memcpy( &temp, fl+i, sizeof(FTYPE) );
  841.                memcpy( fl+i, fl+i+inc, sizeof(FTYPE) );
  842.                memcpy( fl+i+inc, &temp, sizeof(FTYPE) );
  843.                change = i;
  844.             }
  845.          }
  846.          limit = change - inc;
  847.       } while (change);
  848.       inc = inc / 2;
  849.    }
  850. }
  851.